<template>
    <div ref="wrapRef" class="top-goods-rank">
        <div v-if="!loading && !list.length" class="empty">
            {{ emptyText }}
        </div>
    </div>
</template>

<script setup lang="ts">
import { ref, computed, watch, onMounted, onUnmounted, nextTick } from "vue";
import * as echarts from "echarts/core";
import { BarChart } from "echarts/charts";
import { TooltipComponent, GridComponent, LegendComponent } from "echarts/components";
import { CanvasRenderer } from "echarts/renderers";

echarts.use([BarChart, TooltipComponent, GridComponent, LegendComponent, CanvasRenderer]);

/* ---------- props & emits ---------- */
const props = withDefaults(
    defineProps<{
        data?: any[];
        fetch?: () => Promise<any[]>;
        fields?: { name?: string; price?: string; sales?: string; img?: string };
        top?: number;
        title?: string;
        color?: string | string[];
        height?: string | number;
        emptyText?: string;
    }>(),
    {
        fields: () => ({ name: "name", price: "price", sales: "sales", img: "img" }),
        top: 10,
        title: "",
        color: () => ["#83bff6", "#188df0"],
        emptyText: "暂无数据",
    }
);

/* ---------- 基本状态 ---------- */
const wrapRef = ref<HTMLDivElement>();
let chartInst: echarts.ECharts | null = null;
const loading = ref(false);
const remoteData = ref<any[]>([]);
const stopWatch = ref<Function>();

/* ---------- 计算最终数据 ---------- */
const list = computed(() => {
    const src = props.data ?? remoteData.value;
    return src
        .sort((a: any, b: any) => b[props.fields.sales!] - a[props.fields.sales!])
        .slice(0, props.top)
        .map((item: any) => ({
            value: item[props.fields.sales!],
            ...item,
        }));
});

const wrapHeight = computed(() => (typeof props.height === "number" ? `${props.height}px` : props.height));

/* ---------- 图表绘制 ---------- */
function renderChart() {
    if (!wrapRef.value || !list.value.length) return;
    if (!chartInst) {
        chartInst = echarts.init(wrapRef.value);
        stopWatch.value = useResizeObserver(wrapRef.value, () => chartInst?.resize());
    }
    const { name, price, sales, img } = props.fields;
    const option = {
        title: { show: false, text: props.title, left: "center", textStyle: { color: "#fff" } },
        tooltip: {
            trigger: "axis",
            axisPointer: { type: "shadow" },
            formatter: (params: any) => {
                const item = params[0].data;
                return `
                  <div style="text-align:center;">
                    <img src="${item.img}" style="width:64px;height:64px;border-radius:4px;" />
                    <div>${item.name}</div>
                    <div>价格：¥${item.price}</div>
                    <div>销量：${item.sales}</div>
                  </div>
                  `;
            },
        },
        grid: { left: 140, right: 20, top: 20, bottom: 20 },
        xAxis: { type: "value", axisLabel: { color: "#ccc" } },
        yAxis: {
            type: "category",
            inverse: true,
            axisLine: { show: false },
            axisTick: { show: false },
            axisLabel: { show: false }, // ① 关闭 Y 轴 label
        },
        series: [
            {
                type: "bar",
                data: list.value,
                encode: { x: "value", y: name }, // ② 用 encode 指定维度
                itemStyle: {
                    color: Array.isArray(props.color)
                        ? new echarts.graphic.LinearGradient(0, 0, 1, 0, [
                              { offset: 0, color: props.color[0] },
                              { offset: 1, color: props.color[1] },
                          ])
                        : props.color,
                },
                label: {
                    show: true,
                    position: "left",
                    distance: 8,
                    formatter: (params: any) => {
                        const { data } = params;
                        return `${data.name}`;
                    },
                    rich: {
                        img: {
                            width: 40,
                            height: 40,
                            borderRadius: 4,
                            backgroundColor: {
                                image: (params: any) => {
                                    return params.data.img;
                                },
                            },
                        },
                        name: { fontSize: 14, color: "#fff", padding: [0, 0, 0, 8] },
                        price: { fontSize: 12, color: "#ffcc00", padding: [0, 0, 0, 8] },
                    },
                },
            },
        ],
    };
    chartInst.setOption(option, true);
}

/* ---------- 数据获取 ---------- */
async function loadRemote() {
    if (!props.fetch) return;
    loading.value = true;
    try {
        remoteData.value = await props.fetch();
    } finally {
        loading.value = false;
    }
}

/* ---------- 生命周期 ---------- */
onMounted(async () => {
    if (!props.data) await loadRemote();
    nextTick(renderChart);
});

watch(list, () => nextTick(renderChart), { deep: true });

onUnmounted(() => {
    stopWatch.value?.();
    chartInst?.dispose();
});

/* ---------- Resize 工具 ---------- */
function useResizeObserver(el: HTMLElement, fn: () => void) {
    if (!window.ResizeObserver) return () => {};
    const ro = new ResizeObserver(fn);
    ro.observe(el);
    return () => ro.disconnect();
}
</script>

<style lang="scss" scoped>
.top-goods-rank {
    width: 100%;
    height: 100%;
    position: relative;
}
.empty {
    display: flex;
    align-items: center;
    justify-content: center;
    height: 100%;
    color: #666;
}
</style>
